package org.smile.strate.form;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.smile.beans.BeanInfo;
import org.smile.beans.BeanProperties;
import org.smile.beans.FieldDeclare;
import org.smile.beans.MapBean;
import org.smile.beans.PropertyHandler;
import org.smile.beans.converter.BeanException;
import org.smile.beans.handler.MapBeanPropertyHandler;
import org.smile.collection.ArrayUtils;
import org.smile.commons.Strings;
import org.smile.http.RequestUtils;
import org.smile.json.JSONArray;
import org.smile.strate.ActionConstants;
import org.smile.strate.Strate;
import org.smile.strate.StrateException;
import org.smile.strate.action.Action;
import org.smile.strate.action.ActionElement;
import org.smile.strate.action.ClassElement;
import org.smile.strate.api.ApiServiceConstants;
import org.smile.strate.dispatch.ActionURLInfo;
import org.smile.strate.dispatch.DispatchContext;

/**
 * request 数据赋值
 * @author 胡真山
 * @Date 2016年1月19日
 */
public class ActionParameterFiller {
	/**没有属性时不抛出异常*/
	public static MapBeanPropertyHandler handler = new MapBeanPropertyHandler(false);

	/***
	 * 是否是字段提交的值为空
	 * @param value
	 * @return
	 */
	protected static boolean isEmptyField(Object value){
		if(value==null){
			return true;
		}
		if(ArrayUtils.isEmpty(value)){
			return true;
		}
		return false;
	}
	
	/**
	 * 设置request中的数据到action属性中
	 * @param context 目标
	 * @return
	 * @throws BeanException
	 */
	public static ActionFormResult fillRequestToAction(DispatchContext context) throws BeanException {
		ActionFormResult result = new ActionFormResult();
		Action target=context.getAction();
		ActionElement actionElement=context.getActionElement();
		HttpServletRequest request=context.getRequest();
		ActionURLInfo actionUrlInfo=context.getActionUrlInfo();
		if(target.needRequestToAction()){
			BeanProperties beanProperties = new BeanProperties(StrateConverter.getInstance(target.getClass()),false);
			Enumeration<String> names = request.getParameterNames();
			Map<String,String[]> parameters=request.getParameterMap();
			while (names.hasMoreElements()) {
				String key = names.nextElement();
				Object value = doRequestParameterValue(result,parameters,key);
				if (isEmptyField(value)) {
					continue;
				}
				beanProperties.setExpFieldValue(target, RequestUtils.convertArrayKeyToProperty(key), value);
			}
			//处理url中的参数 /{name}/{age}
			doUrlParameterValues(actionElement,result,actionUrlInfo,target,beanProperties);
		}
		return result;
	}


	/**
	 * 表单数据填充到action接收对象参数中
	 * @param context
	 * @param beanClass
	 * @return
	 * @throws BeanException
	 * @throws StrateException
	 */
	public static ActionFormResult fillRequestToAction(DispatchContext context, ActionParamBeanClass beanClass) throws BeanException, StrateException {
		ActionElement actionElement=context.getActionElement();
		Action target=context.getAction();
		HttpServletRequest request=context.getRequest();
		ActionURLInfo actionUrlInfo=context.getActionUrlInfo();
		BeanProperties beanProperties = new BeanProperties(StrateConverter.getInstance(target.getClass()),false);
		MapBean<ActionParamBeanClass> paramBean=beanClass.newInstance();
		String isApi=request.getHeader(ApiServiceConstants.apiSubmitHeader);
		ActionFormResult result = new ActionFormResult();
		if(Strings.TRUE.equals(isApi)) {//是采用api提交的数据
			try {
				String bodyString = beanClass.readRequestBodyAsString(request, Strate.encoding);
				JSONArray jsonArray = new JSONArray(bodyString);
				Set<String> fieldNames = beanClass.getFieldNames();
				int index = 0;
				for (String name : fieldNames) {
					if (index >= jsonArray.size()) {
						break;
					}
					handler.setExpFieldValue(paramBean, name, jsonArray.get(index));
					index++;
				}
			}catch(Exception e){
				throw new StrateException(e);
			}
		}else{
			//读取请求body数据
			if(beanClass.hasRequestBody()) {
				beanClass.doRequestBody(target, paramBean);
			}
			beanClass.setRequestAndResponse(paramBean, request, context.getResponse());
			//参数数据
			Enumeration<String> names = request.getParameterNames();
			//使用新建的 用于对转换器的重写
			paramBean.setBeanProperties(beanProperties);
			Map<String,String[]> parameters=request.getParameterMap();
			while (names.hasMoreElements()) {
				String key = names.nextElement();
				Object value = doRequestParameterValue(result,parameters,key);
				if (isEmptyField(value)) {
					continue;
				}
				key = RequestUtils.convertArrayKeyToProperty(key);
				if(target.needRequestToAction()){//需要设置属性到action对象中
					beanProperties.setExpFieldValue(target, key, value);
				}
				//设置对方法封装的mapBean中
				handler.setExpFieldValue(paramBean, key, value);
			}
		}
		//处理url中的参数 /{name}/{age}
		doUrlParameterValues(actionElement,result,actionUrlInfo,paramBean,handler);
		result.setMethodParamBean(paramBean);
		//把url解析信息添加到
		if(actionUrlInfo.isNeedToAction()) {
			Map.Entry<String,FieldDeclare> fieldDeclare=beanClass.getFieldDeclareByType(ActionURLInfo.class);
			if(fieldDeclare!=null) {
				handler.setExpFieldValue(paramBean, fieldDeclare.getKey(), actionUrlInfo);
			}
		}
		
		return result;
	}

	/**
	 * 处理url中的参数 /{name}/{age}
	 * @param actionElement
	 * @param result
	 * @param actionUrlInfo
	 * @param target
	 * @param propertyHandler
	 * @throws BeanException
	 */
	private static void doUrlParameterValues(ActionElement actionElement, ActionFormResult result, ActionURLInfo actionUrlInfo, Object target, PropertyHandler propertyHandler) throws BeanException {
		if(actionUrlInfo!=null&&actionElement.getUriInfo().hasArgs()) {
			String[] argValues=actionUrlInfo.getUriArgs();
			Map<String,String> values = actionElement.getUriInfo().parserArgsValue(argValues);
			for(Map.Entry<String,String> entry:values.entrySet()) {
				propertyHandler.setExpFieldValue(target, entry.getKey(), entry.getValue());
			}
		}
	}

	/**
	 * 处理request中的参数值
	 * @param result
	 * @param parameters
	 * @param key
	 * @return
	 */
	private static Object doRequestParameterValue(ActionFormResult result, Map parameters, String key){
		// 动态切换方法
		if (ActionConstants.allowDynamicMethod) {
			if (key.startsWith(ActionConstants.dynamicMethodFlag)) {
				String dynamicAction = key.substring(ActionConstants.dynamicMethodFlag.length());
				result.setDynamicAction(dynamicAction);
			}
		}
		Object value = parameters.get(key);
		return value;
	}

	/**
	 * 把action的值设置到request中
	 * @param request
	 * @param target
	 * @throws BeanException
	 */
	public static void fillActionToRequest(HttpServletRequest request, ActionElement actionElement, Action target) throws BeanException {
		if (target == null) {
			return;
		}
		BeanInfo beaninfo = BeanInfo.getInstance(target.getClass());
		PropertyDescriptor[] pds = beaninfo.getPropertyDescriptors();
		ClassElement clazzEle=actionElement.getClassElement();
		for (PropertyDescriptor pd : pds) {
			Method reader = pd.getReadMethod();
			if (reader!= null&&!clazzEle.existsActionByMethodName(reader.getName())) {
				try {
					Object value = reader.invoke(target);
					if (value != null) {
						request.setAttribute(pd.getName(), value);
					}
				} catch (Exception e) {
					throw new BeanException(target.getClass() + "action getter invoke error " + pd, e);
				}
			}
		}
	}
}
